package com.zxy.ziems.server.energy.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.common.collect.Sets;
import com.zxy.btp.common.response.PageResult;
import com.zxy.ziems.server.constant.DateType;
import com.zxy.ziems.server.device.service.DataTypeService;
import com.zxy.ziems.server.device.service.DataUnitService;
import com.zxy.ziems.server.energy.convertor.EnergyEfficiencyLibraryConvertor;
import com.zxy.ziems.server.energy.enums.TimeDimensionEnum;
import com.zxy.ziems.server.energy.mapper.EnergyEfficiencyLibraryMapper;
import com.zxy.ziems.server.energy.pojo.dto.DeviceDataTypeDTO;
import com.zxy.ziems.server.energy.pojo.dto.EnergyEfficiencyLibraryDTO;
import com.zxy.ziems.server.energy.pojo.entity.EnergyEfficiencyLibraryEntity;
import com.zxy.ziems.server.energy.pojo.param.EnergyEfficiencyCompareParam;
import com.zxy.ziems.server.energy.pojo.param.EnergyEfficiencyLibraryParam;
import com.zxy.ziems.server.energy.pojo.vo.EnergyEfficiencyCompareTypeVO;
import com.zxy.ziems.server.energy.pojo.vo.EnergyEfficiencyCompareVO;
import com.zxy.ziems.server.energy.pojo.vo.EnergyEfficiencyLibraryVO;
import com.zxy.ziems.server.energy.service.DeviceMeasureDataDayService;
import com.zxy.ziems.server.energy.service.EnergyEfficiencyLibraryService;
import com.zxy.ziems.server.mybatis.core.service.ServiceImplX;
import com.zxy.ziems.server.utils.AssertUtil;
import com.zxy.ziems.server.utils.BusinessExceptionUtil;
import com.zxy.ziems.server.utils.DateUtils;
import com.zxy.ziems.server.utils.StringUtils;
import com.zxy.ziems.server.vo.ChartVo;
import com.zxy.ziems.server.vo.ChartYAxisVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class EnergyEfficiencyLibraryServiceImpl extends ServiceImplX<EnergyEfficiencyLibraryMapper, EnergyEfficiencyLibraryEntity> implements EnergyEfficiencyLibraryService {

    @Autowired
    private DataTypeService dataTypeService;
    @Autowired
    private DataUnitService dataUnitService;
    @Autowired
    private DeviceMeasureDataDayService deviceMeasureDataDayService;
    @Override
    public PageResult<EnergyEfficiencyLibraryVO> page(EnergyEfficiencyLibraryParam param) {
        return  customPage(param, (page, p) -> baseMapper.queryPageList(page, p));
    }

    @Transactional
    @Override
    public void add(EnergyEfficiencyLibraryDTO dto) {
        checkAddBeforeAction(dto);

        EnergyEfficiencyLibraryEntity entity = EnergyEfficiencyLibraryConvertor.INSTANT.dto2entity(dto);

        save(entity);
    }

    @Transactional
    @Override
    public void modify(EnergyEfficiencyLibraryDTO dto) {
        checkModifyBeforeAction(dto);

        EnergyEfficiencyLibraryEntity entity = EnergyEfficiencyLibraryConvertor.INSTANT.dto2entity(dto);

        updateById(entity);
    }

    @Transactional
    @Override
    public void remove(String id) {
        removeById(id);
    }

    private void checkModifyBeforeAction(EnergyEfficiencyLibraryDTO dto) {
        if (StringUtils.isNotBlank(dto.getDataTypeId())) {
            AssertUtil.nonNull(dataTypeService.getById(dto.getDataTypeId()), "未找到指标");
            checkUnique(dto);
        }
        if (StringUtils.isNotBlank(dto.getDataUnitId())) AssertUtil.nonNull(dataUnitService.getById(dto.getDataUnitId()), "未找到单位");
        if (dto.getDataTypeId() != null) AssertUtil.nonNull(TimeDimensionEnum.getByCode(dto.getTimeDimension()), "时间维度参数错误");
    }

    private void checkAddBeforeAction(EnergyEfficiencyLibraryDTO dto) {
        AssertUtil.nonNull(dataTypeService.getById(dto.getDataTypeId()), "未找到指标");
        AssertUtil.nonNull(dataUnitService.getById(dto.getDataUnitId()), "未找到单位");
        AssertUtil.nonNull(TimeDimensionEnum.getByCode(dto.getTimeDimension()), "时间维度参数错误");
        checkUnique(dto);
    }

    /**
     * 校验相同指标相同时间维度不可重复
     * @param dto
     */
    private void checkUnique(EnergyEfficiencyLibraryDTO dto) {
        QueryWrapper<EnergyEfficiencyLibraryEntity> param = new QueryWrapper<>();
        param.lambda().eq(EnergyEfficiencyLibraryEntity::getDataTypeId, dto.getDataTypeId())
                .eq(EnergyEfficiencyLibraryEntity::getTimeDimension, dto.getTimeDimension());
        if (StringUtils.isNotBlank(dto.getId())) {
            param.lambda().ne(EnergyEfficiencyLibraryEntity::getId, dto.getId());
        }
        AssertUtil.isTrue(baseMapper.selectCount(param) < 1, "指标维度配置重复");
    }

    @Override
    public List<EnergyEfficiencyCompareTypeVO> getDeviceTataType(EnergyEfficiencyCompareParam param) {
        return baseMapper.getDeviceTataType(Arrays.asList(param.getDeviceId1(), param.getDeviceId2()), param.getTimeDimension());
    }

    @Override
    public EnergyEfficiencyCompareVO deviceCompare(EnergyEfficiencyCompareParam param) {

        EnergyEfficiencyCompareVO res = new EnergyEfficiencyCompareVO();

        List<String> deviceIds = Arrays.asList(param.getDeviceId1(), param.getDeviceId2());
        List<EnergyEfficiencyCompareTypeVO> compareTypeList = baseMapper.getDeviceTataType(deviceIds, param.getTimeDimension());

        List<DeviceDataTypeDTO> deviceRelationVal = getDeviceRelationVal(param);

        setCompareVal(compareTypeList, deviceRelationVal, param);

        res.setCompareTypeList(compareTypeList);

        setChat(res);
        return res;
    }

    private void setChat(EnergyEfficiencyCompareVO res) {
        List<EnergyEfficiencyCompareTypeVO> compareTypeList = res.getCompareTypeList();
        if (CollectionUtils.isEmpty(compareTypeList)) return;

        Map<String, EnergyEfficiencyCompareTypeVO> dataMap = compareTypeList.stream().collect(Collectors.toMap(EnergyEfficiencyCompareTypeVO::getDataTypeId, v -> v));

        ChartVo chat = new ChartVo();
        List<String> xList = new ArrayList<>();
        List<ChartYAxisVo> yList = new ArrayList<>();
        ChartYAxisVo yAxisVo1 = new ChartYAxisVo();
        List<BigDecimal> data1 = new ArrayList<>();
        yAxisVo1.setName("实际值-设备1");
        ChartYAxisVo yAxisVo2 = new ChartYAxisVo();
        List<BigDecimal> data2 = new ArrayList<>();
        yAxisVo2.setName("实际值-设备2");

        long standardCount = res.getCompareTypeList().stream().filter(m -> m.getStandard() != null).count();

        List<BigDecimal> dataStandard = new ArrayList<>();

        dataMap.forEach((k, v) -> {
            xList.add(v.getDataTypeName());
            dataStandard.add(v.getStandard());

            data1.add(v.getDeviceVal1());
            data2.add(v.getDeviceVal2());
        });
        yAxisVo1.setData(data1);
        yList.add(yAxisVo1);

        yAxisVo2.setData(data2);
        yList.add(yAxisVo2);

        if (standardCount > 0) {
            ChartYAxisVo yAxisVoStandard = new ChartYAxisVo();
            yAxisVoStandard.setName("标杆值");
            yAxisVoStandard.setData(dataStandard);
            yList.add(yAxisVoStandard);
        }
        chat.setXAxisList(xList);
        chat.setYAxisList(yList);
        res.setChat(chat);
    }

    private void setCompareVal(List<EnergyEfficiencyCompareTypeVO> compareTypeList, List<DeviceDataTypeDTO> deviceRelationVal, EnergyEfficiencyCompareParam param) {
        String deviceId1 = param.getDeviceId1();
        String deviceId2 = param.getDeviceId2();

        Map<String, BigDecimal> map = new HashMap<>();

        if (!CollectionUtils.isEmpty(param.getTypeVOList())) {
            map = param.getTypeVOList().stream().collect(Collectors.toMap(EnergyEfficiencyCompareTypeVO::getDataTypeId, EnergyEfficiencyCompareTypeVO::getStandard));
        }


        Map<String, BigDecimal> deviceValMap = deviceRelationVal.stream().collect(Collectors.toMap(k -> k.getDeviceId() + "-" + k.getDataTypeId(), v -> v.getIncrementValueSum()));
        for (EnergyEfficiencyCompareTypeVO m : compareTypeList) {
            String dataTypeId = m.getDataTypeId();
            BigDecimal standard = map.get(dataTypeId);
            BigDecimal deviceVal1 = deviceValMap.get(deviceId1 + "-" + dataTypeId);
            m.setDeviceVal1(deviceVal1);
            m.setDeviceId1(deviceId1);
            m.setDeviceValDiff1(standard == null ? null : deviceVal1.subtract(standard));
            m.setStandard(standard);

            BigDecimal deviceVal2 = deviceValMap.get(deviceId2 + "-" + dataTypeId);
            m.setDeviceId2(deviceId2);
            m.setDeviceVal2(deviceVal2);
            m.setDeviceValDiff2(standard == null ? null : deviceVal2.subtract(standard));
        }

    }

    /**
     * 获取设备实际值
     * @param param
     */
    private List<DeviceDataTypeDTO> getDeviceRelationVal(EnergyEfficiencyCompareParam param) {
        TimeDimensionEnum timeDimensionEnum = TimeDimensionEnum.getByCode(param.getTimeDimension());
        String date = param.getDate();
        String dataType = null;
        LocalDate start = null;
        LocalDate end = null;
        if (timeDimensionEnum.equals(TimeDimensionEnum.YEAR)) {
            LocalDate date1 = DateUtils.toDate(date, DateUtils.YEAR_PATTERN);
            start = LocalDate.of(date1.getYear(), 1,1);
            end = LocalDate.of(date1.getYear(), 12, 31);
            dataType = DateType.YEAR;
        } else if (timeDimensionEnum.equals(TimeDimensionEnum.MONTH)) {
            LocalDate date1 = DateUtils.toDate(date, DateUtils.YM_PATTERN);
            start = DateUtils.getMonthStartDate(date1);
            end = DateUtils.getMonthEndDate(date1);
            dataType = DateType.MONTH;
        } else {
            BusinessExceptionUtil.exception("时间维度错误");
        }
        return deviceMeasureDataDayService.getDeviceDataTypeSum(dataType, start, end, Sets.newHashSet(param.getDeviceId1(), param.getDeviceId2()));
    }
}
